home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / JTextComponent.java < prev    next >
Text File  |  1998-06-30  |  75KB  |  2,187 lines

  1. /*
  2.  * @(#)JTextComponent.java    1.101 98/04/10
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing.text;
  21.  
  22. import java.util.Hashtable;
  23. import java.util.Enumeration;
  24. import java.io.*;
  25. import java.awt.*;
  26. import java.awt.event.*;
  27. import java.awt.datatransfer.*;
  28. import java.text.*;
  29. import com.sun.java.swing.*;
  30. import com.sun.java.swing.event.*;
  31. import com.sun.java.swing.plaf.*;
  32. import com.sun.java.accessibility.*;
  33.  
  34. /**
  35.  * JTextComponent is the base class for swing text components.  It
  36.  * tries to be compatible with the java.awt.TextComponent class
  37.  * where it can reasonably do so.  Also provided are other services
  38.  * for additional flexibility (beyond the pluggable UI and bean
  39.  * support).
  40.  * <dl>
  41.  * <dt><b><font size=+1>Caret Changes</font></b>
  42.  * <dd>
  43.  * The caret is a pluggable object in swing text components.
  44.  * Notification of changes to the caret position and the selection
  45.  * are sent to implementations of the CaretListener interface that
  46.  * have been registered with the text component.  The UI will
  47.  * install a default caret unless a customized caret has been 
  48.  * set.
  49.  * <dt><b><font size=+1>Commands</font></b>
  50.  * <dd>
  51.  * <p>
  52.  * Text components provide a number of commands that can be used
  53.  * to manipulate the component.  This is essentially the way that
  54.  * the component expresses its capabilities.  These are expressed
  55.  * in terms of the swing Action interface, using the TextAction
  56.  * implementation.  The set of commands supported by the text
  57.  * component can be found with the 
  58.  * <a href="#getActions">getActions</a> method.  These actions
  59.  * can be bound to key events, fired from buttons, etc.
  60.  *
  61.  * <dt><b><font size=+1>Keymaps</font></b>
  62.  * <dd>
  63.  * <p>
  64.  * To facilitate flexible use of the keyboard, support for
  65.  * creating keymaps and binding various keystrokes to some kind of 
  66.  * action is provided.  In order to allow keymaps to be shared across 
  67.  * multiple text components, they can use actions that extend TextAction.  
  68.  * TextAction can determine which JTextComponent most recently has or had
  69.  * focus and therefore is the subject of the action (In the case that the 
  70.  * ActionEvent sent to the action doesn't contain the target text component 
  71.  * as its source).
  72.  * <p>
  73.  * The use of the keymap is encouraged, but backward compatibilty
  74.  * with the awt mechanism is provided by giving the 
  75.  * listeners a chance to steal the event by consuming it.
  76.  * Keyboard event distribution is handled in the following order, with
  77.  * each distribution capable of consuming the event.
  78.  * <ol>
  79.  * <li>focus manager
  80.  * <li>registered KeyListener's
  81.  * <li>keymap handling using the current keymap
  82.  * <li>keyboard handling in JComponent (e.g. accelerators,
  83.  * component navigation, etc.).
  84.  * </ol>
  85.  * <p>
  86.  * By default the component will create a keymap (named <b>DEFAULT_KEYMAP</b>) 
  87.  * that is shared by all JTextComponent instances as the default keymap.  
  88.  * Typically a look-and-feel implementation will install a different keymap
  89.  * that resolves to the default keymap for those bindings not found in the 
  90.  * different keymap. The minimal bindings include:
  91.  * <ul>
  92.  * <li>inserting content into the editor for the
  93.  *  printable keys.
  94.  * <li>removing content with the backspace and del
  95.  *  keys.
  96.  * <li>caret movement forward and backward
  97.  * </ul>
  98.  *
  99.  * <dt><b><font size=+1>Model/View Split</font></b>
  100.  * <dd>
  101.  * <p>
  102.  * The text components have a model-view split.  A text component pulls 
  103.  * together the objects used to represent the model, view, and controller. 
  104.  * The text document model may be shared by other views which act as observers 
  105.  * of the model (e.g. a document may be shared by multiple components).
  106.  *
  107.  * <p align=center><img src="doc-files/editor.gif" HEIGHT=358 WIDTH=587></p>
  108.  *
  109.  * <p>
  110.  * The model is defined by the
  111.  * <a href="com.sun.java.swing.text.Document.html">Document</a>
  112.  * interface.  This is intended to provide a flexible text storage mechanism
  113.  * that tracks change during edits and can be extended to more sophisticated
  114.  * models.  The model interfaces are meant to capture the capabilities of
  115.  * expression given by SGML, a system used to express a wide variety of
  116.  * content.
  117.  * Each modification to the document causes notification of the
  118.  * details of the change to be sent to all observers in the form of a 
  119.  * <a href="com.sun.java.swing.event.DocumentEvent.html">DocumentEvent</a>
  120.  * which allows the views to stay up to date with the model.
  121.  * This event is sent to observers that have implemented the 
  122.  * <a href="com.sun.java.swing.event.DocumentListener.html">DocumentListener</a>
  123.  * interface and registered interest with the model being observed.
  124.  *
  125.  * <dt><b><font size=+1>Location Information</font></b>
  126.  * <dd>
  127.  * The capability of determining the location of text in
  128.  * the view is provided.  There are two methods, 
  129.  * <a href="#modelToView">modelToView</a> and
  130.  * <a href="#viewToModel">viewToModel</a> for determining
  131.  * this information.
  132.  * <dt><b><font size=+1>Undo/Redo support</font></b>
  133.  * <dd>
  134.  * Support for an edit history mechanism is provided to allow
  135.  * undo/redo operations.  The text component does not itself
  136.  * provide the history buffer by default, but does provide
  137.  * the UndoableEdit records that can be used in conjunction
  138.  * with a history buffer to provide the undo/redo support.
  139.  * The support is provided by the Document model, which allows
  140.  * one to attach UndoableEditListener implementations.
  141.  *
  142.  * <dt><b><font size=+1>Thread Safety</font></b>
  143.  * <dd>
  144.  * The swing text components provide some support of thread
  145.  * safe operations.  Because of the high level of configurability
  146.  * of the text components, it is possible to circumvent the
  147.  * protection provided.  The protection primarily comes from
  148.  * the model, so the documentation of AbstractDocument
  149.  * describes the assumptions of the protection provided.
  150.  * The methods that are safe to call asynchronously are marked
  151.  * with comments.
  152.  * </dl>
  153.  *
  154.  * <p>
  155.  * Warning: serialized objects of this class will not be compatible with
  156.  * future swing releases.  The current serialization support is appropriate
  157.  * for short term storage or RMI between Swing1.0 applications.  It will
  158.  * not be possible to load serialized Swing1.0 objects with future releases
  159.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  160.  * baseline for the serialized form of Swing objects.
  161.  *
  162.  * @beaninfo
  163.  *     attribute: isContainer false
  164.  * 
  165.  * @author  Timothy Prinzing
  166.  * @version 1.101 04/10/98
  167.  * @see Document
  168.  * @see DocumentEvent
  169.  * @see DocumentListener
  170.  * @see Caret
  171.  * @see CaretEvent
  172.  * @see CaretListener
  173.  * @see TextUI
  174.  * @see View
  175.  * @see ViewFactory
  176.  */
  177. public abstract class JTextComponent extends JComponent implements Scrollable,
  178. Accessible
  179. {
  180.  
  181.     /**
  182.      * Creates a new JTextComponent.
  183.      * Listeners for caret events are established, and the pluggable
  184.      * UI installed.  The component is marked as editable.  No layout manager
  185.      * is used, because layout is managed by the view subsystem of text.
  186.      * The document model is set to null.
  187.      */
  188.     public JTextComponent() {
  189.         super();
  190.         enableEvents(AWTEvent.KEY_EVENT_MASK);
  191.         caretEvent = new MutableCaretEvent(this);
  192.         addMouseListener(caretEvent);
  193.         addFocusListener(caretEvent);
  194.         setEditable(true);
  195.         setLayout(null); // layout is managed by View hierarchy
  196.         updateUI();
  197.     }
  198.  
  199.     /**
  200.      * Fetches the user-interface factory for this text-oriented editor.
  201.      *
  202.      * @return the factory
  203.      */
  204.     public TextUI getUI() { return (TextUI)ui; }
  205.  
  206.     /**
  207.      * Sets the user-interface factory for this text-oriented editor
  208.      *
  209.      * @param ui the factory
  210.      */
  211.     public void setUI(TextUI ui) {
  212.         super.setUI(ui);
  213.     }
  214.  
  215.     /**
  216.      * Reloads the pluggable UI.  The key used to fetch the
  217.      * new interface is <b>getUIClassID()</b>.  The type of
  218.      * the UI is <b>TextUI</b>.  invalidate() is called after
  219.      * setting the UI.
  220.      */
  221.     public void updateUI() {
  222.         setUI((TextUI)UIManager.getUI(this));
  223.         invalidate();
  224.     }
  225.  
  226.  
  227.     /**
  228.      * Returns true if this component is completely opaque.  
  229.      * This is used in painting backgrounds.
  230.      * 
  231.      * @return true if this component is completely opaque.
  232.      */
  233.     public boolean isOpaque() {
  234.         return opaque;
  235.     }
  236.  
  237.     /**
  238.      * Sets whether or not the UI should render a background.
  239.      *
  240.      * @param o true if should render a background
  241.      */
  242.     public void setOpaque(boolean o) {
  243.         opaque = o;
  244.     }
  245.  
  246.     /**
  247.      * Adds a caret listener for notification of any changes
  248.      * to the caret.
  249.      *
  250.      * @param listener the listener
  251.      * @see com.sun.java.swing.event.CaretEvent
  252.      */
  253.     public void addCaretListener(CaretListener listener) {
  254.         listenerList.add(CaretListener.class, listener);
  255.     }
  256.  
  257.     /**
  258.      * Removes a caret listener.
  259.      *
  260.      * @param listener the listener
  261.      * @see com.sun.java.swing.event.CaretEvent
  262.      */
  263.     public void removeCaretListener(CaretListener listener) {
  264.         listenerList.remove(CaretListener.class, listener);
  265.     }
  266.  
  267.     /**
  268.      * Notifies all listeners that have registered interest for
  269.      * notification on this event type.  The event instance 
  270.      * is lazily created using the parameters passed into 
  271.      * the fire method.  The listener list is processed in a
  272.      * last-to-first manner.
  273.      *
  274.      * @param e the event
  275.      * @see EventListenerList
  276.      */
  277.     protected void fireCaretUpdate(CaretEvent e) {
  278.         // Guaranteed to return a non-null array
  279.         Object[] listeners = listenerList.getListenerList();
  280.         // Process the listeners last to first, notifying
  281.         // those that are interested in this event
  282.         for (int i = listeners.length-2; i>=0; i-=2) {
  283.             if (listeners[i]==CaretListener.class) {
  284.                 ((CaretListener)listeners[i+1]).caretUpdate(e);
  285.             }
  286.         }
  287.     }
  288.  
  289.     /**
  290.      * Associates the editor with a text document.
  291.      * The currently registered factory is used to build a view for
  292.      * the document, which gets displayed by the editor after revalidation.
  293.      * A PropertyChange event ("document") is propagated to each listener.
  294.      *
  295.      * @param doc  the document to display/edit
  296.      * @see #getDocument
  297.      * @beaninfo
  298.      *  description: the text document model
  299.      *        bound: true
  300.      *       expert: true
  301.      */
  302.     public void setDocument(Document doc) {
  303.         if (accessibleContext != null) {
  304.             model.removeDocumentListener(
  305.                 ((AccessibleJTextComponent)accessibleContext));
  306.         }
  307.         Document old = model;
  308.         model = doc;
  309.         firePropertyChange("document", old, doc);
  310.         revalidate();
  311.         repaint();
  312.         if (accessibleContext != null) {
  313.             model.addDocumentListener(
  314.                 ((AccessibleJTextComponent)accessibleContext));
  315.         }
  316.     }
  317.  
  318.     /**
  319.      * Fetches the model associated with the editor.  This is
  320.      * primarily for the UI to get at the minimal amount of
  321.      * state required to be a text editor.  Subclasses will
  322.      * return the actual type of the model which will typically
  323.      * be something that extends Document.
  324.      *
  325.      * @return the model
  326.      */
  327.     public Document getDocument() {
  328.         return model;
  329.     }
  330.  
  331.     /**
  332.      * Fetches the command list for the editor.  This is
  333.      * the list of commands supported by the plugged-in UI
  334.      * augmented by the collection of commands that the
  335.      * editor itself supports.  These are useful for binding
  336.      * to events, such as in a keymap.
  337.      *
  338.      * @return the command list
  339.      */
  340.     public Action[] getActions() {      
  341.         return getUI().getEditorKit().getActions(); 
  342.     }
  343.  
  344.     /**
  345.      * Sets margin space between the text component's border
  346.      * and its text. Setting it to null will cause the text component
  347.      * to use a default margin.  The text component's default Border
  348.      * object will use this value to create the proper margin.
  349.      * However, if a non-default border is set on the text component, 
  350.      * it is that Border object's responsibility to create the
  351.      * appropriate margin space (else this property will effectively 
  352.      * be ignored).  This causes a redraw of the component.
  353.      * A PropertyChange event ("margin") is sent to all listeners.
  354.      *
  355.      * @param m the space between the border and the text
  356.      * @beaninfo
  357.      *  description: desired space between the border and text area
  358.      *        bound: true
  359.      */
  360.     public void setMargin(Insets m) {
  361.         Insets old = margin;
  362.         margin = m;
  363.         firePropertyChange("margin", old, m);
  364.         invalidate();
  365.     }
  366.  
  367.     /**
  368.      * Returns the margin between the text component's border and
  369.      * its text.  If no margin has been set, a default value from the UI
  370.      * is returned.
  371.      *
  372.      * @return the margin
  373.      */
  374.     public Insets getMargin() {
  375.         if(margin == null) {
  376.             return ((TextUI)ui).getDefaultMargin();
  377.         } else {
  378.             return margin;
  379.         }
  380.     }
  381.  
  382.     /**
  383.      * Fetches the caret that allows text-oriented navigation over
  384.      * the view.  
  385.      *
  386.      * @return the caret
  387.      */
  388.     public Caret getCaret() {
  389.         return caret;
  390.     }
  391.  
  392.     /**
  393.      * Sets the caret to be used.  By default this will be set
  394.      * by the UI that gets installed.  This can be changed to
  395.      * a custom caret if desired.  Setting the caret results in a
  396.      * PropertyChange event ("caret") being fired.
  397.      *
  398.      * @param c the caret
  399.      * @see #getCaret
  400.      * @beaninfo
  401.      *  description: the caret used to select/navigate
  402.      *        bound: true
  403.      *       expert: true
  404.      */
  405.     public void setCaret(Caret c) {
  406.         if (caret != null) {
  407.             caret.removeChangeListener(caretEvent);
  408.             caret.deinstall(this);
  409.         }
  410.         Caret old = caret;
  411.         caret = c;
  412.         if (caret != null) {
  413.             caret.install(this);
  414.             caret.addChangeListener(caretEvent);
  415.         }
  416.         firePropertyChange("caret", old, caret);
  417.     }
  418.  
  419.     /**
  420.      * Fetches the object responsible for making highlights.
  421.      *
  422.      * @return the highlighter
  423.      */
  424.     public Highlighter getHighlighter() {
  425.         return highlighter;
  426.     }
  427.  
  428.     /**
  429.      * Sets the highlighter to be used.  By default this will be set
  430.      * by the UI that gets installed.  This can be changed to
  431.      * a custom highlighter if desired.  The highlighter can be set to
  432.      * null to disable it.  A PropertyChange event ("highlighter") is fired
  433.      * when a new highlighter is installed.
  434.      *
  435.      * @param h the highlighter
  436.      * @see #getHighlighter
  437.      * @beaninfo
  438.      *  description: object responsible for background highlights
  439.      *        bound: true
  440.      *       expert: true
  441.      */
  442.     public void setHighlighter(Highlighter h) {
  443.         if (highlighter != null) {
  444.             highlighter.deinstall(this);
  445.         }
  446.         Highlighter old = highlighter;
  447.         highlighter = h;
  448.         if (highlighter != null) {
  449.             highlighter.install(this);
  450.         }
  451.         firePropertyChange("highlighter", old, h);
  452.     }
  453.  
  454.     /**
  455.      * Sets the keymap to use for binding events to
  456.      * actions.  Setting to null effectively disables keyboard input.
  457.      * A PropertyChange event ("keymap") is fired when a new keymap
  458.      * is installed.
  459.      *
  460.      * @param map the keymap
  461.      * @see #getKeymap
  462.      * @beaninfo
  463.      *  description: set of key event to action bindings to use
  464.      *        bound: true
  465.      */
  466.     public void setKeymap(Keymap map) {
  467.         Keymap old = keymap;
  468.         keymap = map;
  469.         firePropertyChange("keymap", old, keymap);
  470.     }
  471.  
  472.     /**
  473.      * Fetches the keymap currently active in this text
  474.      * component.
  475.      *
  476.      * @return the keymap
  477.      */
  478.     public Keymap getKeymap() {
  479.         return keymap;
  480.     }
  481.  
  482.     /**
  483.      * Adds a new keymap into the keymap hierarchy.  Keymap bindings
  484.      * resolve from bottom up so an attribute specified in a child
  485.      * will override an attribute specified in the parent.
  486.      *
  487.      * @param nm   the name of the keymap (must be unique within the
  488.      *   collection of named keymaps in the document).  The name may 
  489.      *   be null if the keymap is unnamed, but the caller is responsible
  490.      *   for managing the reference returned as an unnamed keymap can't
  491.      *   be fetched by name.  
  492.      * @param parent the parent keymap.  This may be null if unspecified
  493.      *   bindings need not be resolved in some other keymap.
  494.      * @return the keymap
  495.      */
  496.     public static Keymap addKeymap(String nm, Keymap parent) {
  497.         Keymap map = new DefaultKeymap(nm, parent); 
  498.         if (nm != null) {
  499.             // add a named keymap, a class of bindings
  500.             keymapTable.put(nm, map);
  501.         }
  502.         return map;
  503.     }
  504.  
  505.     /**
  506.      * Removes a named keymap previously added to the document.  Keymaps
  507.      * with null names may not be removed in this way.
  508.      *
  509.      * @param nm  the name of the keymap to remove
  510.      * @return the keymap that was removed
  511.      */
  512.     public static Keymap removeKeymap(String nm) {
  513.         return (Keymap) keymapTable.remove(nm);
  514.     }
  515.  
  516.     /**
  517.      * Fetches a named keymap previously added to the document.
  518.      * This does not work with null-named keymaps.
  519.      *
  520.      * @param nm  the name of the keymap
  521.      * @return the keymap
  522.      */
  523.     public static Keymap getKeymap(String nm) {
  524.         return (Keymap) keymapTable.get(nm);
  525.     }
  526.  
  527.     /**
  528.      * Binding record for creating key bindings.
  529.      * <p>
  530.      * Warning: serialized objects of this class will not be compatible with
  531.      * future swing releases.  The current serialization support is appropriate
  532.      * for short term storage or RMI between Swing1.0 applications.  It will
  533.      * not be possible to load serialized Swing1.0 objects with future releases
  534.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  535.      * baseline for the serialized form of Swing objects.
  536.      */
  537.     public static class KeyBinding {
  538.         
  539.         /**
  540.          * The key.
  541.          */
  542.         public KeyStroke key;
  543.  
  544.         /**
  545.          * The name of the action for the key.
  546.          */
  547.         public String actionName;
  548.  
  549.         /**
  550.          * Creates a new key binding.
  551.          *
  552.          * @param key the key
  553.          * @param actionName the name of the action for the key
  554.          */
  555.         public KeyBinding(KeyStroke key, String actionName) {
  556.             this.key = key;
  557.             this.actionName = actionName;
  558.         }
  559.     }
  560.  
  561.     /**
  562.      * <p>
  563.      * Loads a keymap with a bunch of 
  564.      * bindings.  This can be used to take a static table of
  565.      * definitions and load them into some keymap.  The following
  566.      * example illustrates an example of binding some keys to
  567.      * the cut, copy, and paste actions associated with a 
  568.      * JTextComponent.  A code fragment to accomplish
  569.      * this might look as follows:
  570.      * <pre><code>
  571.      *
  572.      *   static final JTextComponent.KeyBinding[] defaultBindings = {
  573.      *     new JTextComponent.KeyBinding(
  574.      *       KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK),
  575.      *       DefaultEditorKit.copyAction),
  576.      *     new JTextComponent.KeyBinding(
  577.      *       KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK),
  578.      *       DefaultEditorKit.pasteAction),
  579.      *     new JTextComponent.KeyBinding(
  580.      *       KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK),
  581.      *       DefaultEditorKit.cutAction),
  582.      *   };
  583.      *
  584.      *   JTextComponent c = new JTextPane();
  585.      *   Keymap k = c.getKeymap();
  586.      *   JTextComponent.loadKeymap(k, defaultBindings, c.getActions());
  587.      * 
  588.      * </code></pre>
  589.      * The sets of bindings and actions may be empty but must be non-null.
  590.      *
  591.      * @param map the keymap
  592.      * @param bindings the bindings
  593.      * @param actions the set of actions
  594.      */
  595.     public static void loadKeymap(Keymap map, KeyBinding[] bindings, Action[] actions) {
  596.         Hashtable h = new Hashtable();
  597.         for (int i = 0; i < actions.length; i++) {
  598.             Action a = actions[i];
  599.             String value = (String)a.getValue(Action.NAME);
  600.             h.put((value!=null ? value:""), a);
  601.         }
  602.         for (int i = 0; i < bindings.length; i++) {
  603.             Action a = (Action) h.get(bindings[i].actionName);
  604.             if (a != null) {
  605.                 map.addActionForKeyStroke(bindings[i].key, a);
  606.             }
  607.         }
  608.     }
  609.  
  610.     /**
  611.      * Maps an event to an action if one is defined in the 
  612.      * installed keymap, and perform the action.  If the action is 
  613.      * performed, the event is consumed.
  614.      *
  615.      * @returns true if an action was performed, false otherwise.
  616.      */
  617.     private final boolean mapEventToAction(KeyEvent e) {
  618.         Keymap binding = getKeymap();
  619.         if (binding != null) {
  620.             KeyStroke k = KeyStroke.getKeyStrokeForEvent(e);
  621.             Action a = binding.getAction(k);
  622.             if (a != null) {
  623.                 String command = null;
  624.                 if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
  625.                     command = String.valueOf(e.getKeyChar());
  626.                 }
  627.                 ActionEvent ae =  new ActionEvent(this, 
  628.                                                   ActionEvent.ACTION_PERFORMED, 
  629.                                                   command, e.getModifiers());
  630.                 a.actionPerformed(ae);
  631.                 e.consume();
  632.                 return true;
  633.             }
  634.         }
  635.         return false;
  636.     }
  637.  
  638.     /**
  639.      * Fetches the current color used to render the 
  640.      * caret.
  641.      *
  642.      * @return the color
  643.      */
  644.     public Color getCaretColor() {
  645.         return caretColor;
  646.     }
  647.  
  648.     /**
  649.      * Sets the current color used to render the
  650.      * caret.  Setting to null effectively restores the default color.
  651.      * Setting the color results in a PropertyChange event ("caretColor")
  652.      * being fired.
  653.      *
  654.      * @param c the color
  655.      * @see #getCaretColor
  656.      * @beaninfo
  657.      *  description: the color used to render the caret
  658.      *        bound: true
  659.      *    preferred: true
  660.      */
  661.     public void setCaretColor(Color c) {
  662.         Color old = caretColor;
  663.         caretColor = c;
  664.         firePropertyChange("caretColor", old, caretColor);
  665.     }
  666.  
  667.     /**
  668.      * Fetches the current color used to render the 
  669.      * selection.
  670.      *
  671.      * @return the color
  672.      */
  673.     public Color getSelectionColor() {
  674.         return selectionColor;
  675.     }
  676.  
  677.     /**
  678.      * Sets the current color used to render the
  679.      * selection.  Setting the color to null is the same as setting
  680.      * Color.white.  Setting the color results in a PropertyChange event
  681.      * ("selectionColor").
  682.      *
  683.      * @param c the color
  684.      * @see #getSelectionColor
  685.      * @beaninfo
  686.      *  description: color used to render selection background
  687.      *        bound: true
  688.      *    preferred: true
  689.      */
  690.     public void setSelectionColor(Color c) {
  691.         Color old = selectionColor;
  692.         selectionColor = c;
  693.         firePropertyChange("selectionColor", old, selectionColor);
  694.     }
  695.  
  696.     /**
  697.      * Fetches the current color used to render the 
  698.      * selected text.
  699.      *
  700.      * @return the color
  701.      */
  702.     public Color getSelectedTextColor() {
  703.         return selectedTextColor;
  704.     }
  705.  
  706.     /**
  707.      * Sets the current color used to render the
  708.      * selected text.  Setting the color to null is the same as Color.black.
  709.      * Setting the color results in a PropertyChange event
  710.      * ("selectedTextColor") being fired.
  711.      *
  712.      * @param c the color
  713.      * @see #getSelectedTextColor
  714.      * @beaninfo
  715.      *  description: color used to render selected text
  716.      *        bound: true
  717.      *    preferred: true
  718.      */
  719.     public void setSelectedTextColor(Color c) {
  720.         Color old = selectedTextColor;
  721.         selectedTextColor = c;
  722.         firePropertyChange("selectedTextColor", old, selectedTextColor);
  723.     }
  724.  
  725.     /**
  726.      * Fetches the current color used to render the 
  727.      * selected text.
  728.      *
  729.      * @return the color
  730.      */
  731.     public Color getDisabledTextColor() {
  732.         return disabledTextColor;
  733.     }
  734.  
  735.     /**
  736.      * Sets the current color used to render the
  737.      * disabled text.  Setting the color fires off a
  738.      * PropertyChange event ("disabledTextColor").
  739.      *
  740.      * @param c the color
  741.      * @see #getDisabledTextColor
  742.      * @beaninfo
  743.      *  description: color used to render disabled text
  744.      *        bound: true
  745.      *    preferred: true
  746.      */
  747.     public void setDisabledTextColor(Color c) {
  748.         Color old = disabledTextColor;
  749.         disabledTextColor = c;
  750.         firePropertyChange("disabledTextColor", old, disabledTextColor);
  751.     }
  752.  
  753.     /**
  754.      * Replaces the currently selected content with new content
  755.      * represented by the given string.  If there is no selection
  756.      * this amounts to an insert of the given text.  If there
  757.      * is no replacement text this amounts to a removal of the
  758.      * current selection.  
  759.      * <p>
  760.      * This is the method that is used by the default implementation
  761.      * of the action for inserting content that gets bound to the
  762.      * keymap actions.
  763.      * <p>
  764.      * This method is thread safe, although most Swing methods
  765.      * are not. Please see 
  766.      * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
  767.      * and Swing</A> for more information.     
  768.      * <p>
  769.      * If the component is not currently editable, beep and return.  Then if
  770.      * the underlying model is null, do nothing.
  771.      *
  772.      * @param content  the content to replace the selection with
  773.      */
  774.     public void replaceSelection(String content) {
  775.         if (! isEditable()) {
  776.             getToolkit().beep();
  777.             return;
  778.         }
  779.         Document doc = getDocument();
  780.         if (doc != null) {
  781.             try {
  782.                 int p0 = Math.min(caret.getDot(), caret.getMark());
  783.                 int p1 = Math.max(caret.getDot(), caret.getMark());
  784.                 if (p0 != p1) {
  785.                     doc.remove(p0, p1 - p0);
  786.                 }
  787.                 if (content != null && content.length() > 0) {
  788.                     doc.insertString(p0, content, null);
  789.                 }
  790.             } catch (BadLocationException e) {
  791.                 getToolkit().beep();
  792.             }
  793.         }
  794.     }
  795.  
  796.     /**
  797.      * Fetches a portion of the text represented by the
  798.      * component.  Returns an empty string if length is 0.
  799.      *
  800.      * @param offs the offset >= 0
  801.      * @param len the length >= 0
  802.      * @return the text
  803.      * @exception BadLocationException if the offset or length are invalid
  804.      */
  805.     public String getText(int offs, int len) throws BadLocationException {
  806.         return getDocument().getText(offs, len);
  807.     }
  808.  
  809.     /**
  810.      * Converts the given location in the model to a place in
  811.      * the view coordinate system.
  812.      *
  813.      * @param pos the position >= 0
  814.      * @return the coordinates as a rectangle, with (r.x, r.y) as the location
  815.      *   in the coordinate system
  816.      * @exception BadLocationException if the given position does not 
  817.      *   represent a valid location in the associated document
  818.      * @see TextUI#modelToView
  819.      */
  820.     public Rectangle modelToView(int pos) throws BadLocationException {
  821.         return getUI().modelToView(pos);
  822.     }
  823.  
  824.     /**
  825.      * Converts the given place in the view coordinate system
  826.      * to the nearest representative location in the model.
  827.      *
  828.      * @param pt the location in the view to translate
  829.      * @return the offset >= 0 from the start of the document
  830.      * @see TextUI#viewToModel
  831.      */
  832.     public int viewToModel(Point pt) {
  833.         return getUI().viewToModel(pt);
  834.     }
  835.  
  836.     /**
  837.      * Transfers the currently selected range in the associated
  838.      * text model to the system clipboard, removing the contents
  839.      * from the model.  The current selection is reset.  Does nothing
  840.      * for null selections.
  841.      */
  842.     public void cut() {
  843.         try {
  844.             Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  845.             int p0 = Math.min(caret.getDot(), caret.getMark());
  846.             int p1 = Math.max(caret.getDot(), caret.getMark());
  847.             if (p0 != p1) {
  848.                 Document doc = getDocument();
  849.                 String srcData = doc.getText(p0, p1 - p0);
  850.                 StringSelection contents = new StringSelection(srcData);
  851.                 clipboard.setContents(contents, defaultClipboardOwner);
  852.                 doc.remove(p0, p1 - p0);
  853.             }
  854.         } catch (BadLocationException e) {
  855.         }
  856.     }
  857.  
  858.     /**
  859.      * Transfers the currently selected range in the associated
  860.      * text model to the system clipboard, leaving the contents
  861.      * in the text model.  The current selection is remains intact.
  862.      * Does nothing for null selections.
  863.      */
  864.     public void copy() {
  865.         try {
  866.             Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  867.             int p0 = Math.min(caret.getDot(), caret.getMark());
  868.             int p1 = Math.max(caret.getDot(), caret.getMark());
  869.             if (p0 != p1) {
  870.                 Document doc = getDocument();
  871.                 String srcData = doc.getText(p0, p1 - p0);
  872.                 StringSelection contents = new StringSelection(srcData);
  873.                 clipboard.setContents(contents, defaultClipboardOwner);
  874.             }
  875.         } catch (BadLocationException e) {
  876.         }
  877.     }
  878.     
  879.     /**
  880.      * Transfers the contents of the system clipboard into the
  881.      * associated text model.  If there is a selection in the
  882.      * associated view, it is replaced with the contents of the
  883.      * clipboard.  If there is no selection, the clipboard contents
  884.      * are inserted in front of the current insert position in 
  885.      * the associated view.  If the clipboard is empty, does nothing.
  886.      * @see #replaceSelection
  887.      */ 
  888.     public void paste() {
  889.         Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  890.         Transferable content = clipboard.getContents(this);
  891.         if (content != null) {
  892.             try {
  893.                 String dstData = (String)(content.getTransferData(DataFlavor.stringFlavor));
  894.                 replaceSelection(dstData);
  895.             } catch (Exception e) {
  896.                 System.err.println("Couldn't get clipboard contents in format: "+
  897.                                    DataFlavor.stringFlavor.getHumanPresentableName());         
  898.             }
  899.         }
  900.     }
  901.  
  902.     /**
  903.      * Moves the caret to a new position, leaving behind a
  904.      * mark defined by the last time setCaretPosition was
  905.      * called.  This forms a selection.
  906.      *
  907.      * @param pos the position
  908.      * @see #setCaretPosition
  909.      */
  910.     public void moveCaretPosition(int pos) {
  911.         caret.moveDot(pos);
  912.     }
  913.  
  914.     /**
  915.      * The bound property name for the focus accelerator.
  916.      */ 
  917.     public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey";
  918.  
  919.     /**
  920.      * Sets the key accelerator that will cause the receiving text
  921.      * component to get the focus.  The accelerator will be the 
  922.      * key combination of the <em>alt</em> key and the character
  923.      * given (converted to upper case).  By default, there is no focus
  924.      * accelerator key.  Any previous key accelerator setting will be
  925.      * superseded.  A '\0' key setting will be registered, and has the
  926.      * effect of turning off the focus accelerator.  When the new key
  927.      * is set, a PropertyChange event (FOCUS_ACCELERATOR_KEY) will be fired.
  928.      *
  929.      * @param aKey the key
  930.      * @see getFocusAccelerator
  931.      * @beaninfo
  932.      *  description: accelerator character used to grab focus
  933.      *        bound: true
  934.      */
  935.     public void setFocusAccelerator(char aKey) {
  936.         aKey = Character.toUpperCase(aKey);
  937.         KeyStroke[] keyStrokes = getRegisteredKeyStrokes();
  938.         int i,c;
  939.         for(i=0,c=keyStrokes.length;i<c;i++) {
  940.             if(getActionForKeyStroke(keyStrokes[i]) == focusAction) {
  941.                 if(keyStrokes[i].getKeyChar() == aKey)
  942.                     return;
  943.                 else
  944.                     unregisterKeyboardAction(keyStrokes[i]);
  945.                 break;
  946.             }
  947.         }
  948.         if(aKey != '\0') {
  949.             registerKeyboardAction(focusAction,KeyStroke.getKeyStroke(aKey,ActionEvent.ALT_MASK),
  950.                                    JComponent.WHEN_IN_FOCUSED_WINDOW);
  951.         }
  952.         char old = focusAccelerator;
  953.         focusAccelerator = aKey;
  954.         firePropertyChange(FOCUS_ACCELERATOR_KEY, old, focusAccelerator);
  955.     }
  956.  
  957.     /**
  958.      * Returns the key accelerator that will cause the receiving
  959.      * text component to get the focus.  Return '\0' if no focus
  960.      * accelerator has been set.
  961.      *
  962.      * @return the key
  963.      */
  964.     public char getFocusAccelerator() {
  965.         return focusAccelerator;
  966.     }
  967.  
  968.     /**
  969.      * Initializes from a stream.  This creates a
  970.      * model of the type appropriate for the component
  971.      * and initializes the model from the stream.
  972.      * By default this will load the model as plain
  973.      * text.  Previous contents of the model are discarded.
  974.      *
  975.      * @param in The stream to read from
  976.      * @param desc An object describing the stream.  This
  977.      *   might be a string, a File, a URL, etc.  Some kinds
  978.      *   of documents (such as html for example) might be
  979.      *   able to make use of this information.  If non-null, it is
  980.      *   added as a property of the document.
  981.      * @exception IOException as thrown by the stream being
  982.      *  used to initialize.
  983.      * @see EditorKit#createDefaultDocument
  984.      * @see #setDocument
  985.      * @see PlainDocument
  986.      */
  987.     public void read(Reader in, Object desc) throws IOException {
  988.         EditorKit kit = getUI().getEditorKit();
  989.         Document doc = kit.createDefaultDocument();
  990.         if (desc != null) {
  991.             doc.putProperty(Document.StreamDescriptionProperty, desc);
  992.         }
  993.         try {
  994.             kit.read(in, doc, 0);
  995.             setDocument(doc);
  996.         } catch (BadLocationException e) {
  997.             throw new IOException(e.getMessage());
  998.         }
  999.     }
  1000.  
  1001.     /**
  1002.      * Stores the contents of the model into the given
  1003.      * stream.  By default this will store the model as plain
  1004.      * text.
  1005.      *
  1006.      * @param out the output stream
  1007.      * @exception IOException on any I/O error
  1008.      */
  1009.     public void write(Writer out) throws IOException {
  1010.         Document doc = getDocument();
  1011.         try {
  1012.             getUI().getEditorKit().write(out, doc, 0, doc.getLength());
  1013.         } catch (BadLocationException e) {
  1014.             throw new IOException(e.getMessage());
  1015.         }
  1016.     }
  1017.  
  1018.     // --- java.awt.Component methods ----------------------------
  1019.  
  1020.     /**
  1021.      * Enables or disables this component, depending on the value of the 
  1022.      * parameter <code>b</code>. An enabled component can respond to user 
  1023.      * input and generate events. Components are enabled initially by default.
  1024.      * A repaint() is done after setting the new state.
  1025.      *
  1026.      * @param     b   If <code>true</code>, this component is 
  1027.      *            enabled; otherwise this component is disabled.
  1028.      * @see #isEnabled
  1029.      * @since JDK1.1
  1030.      */
  1031.     public void setEnabled(boolean b) {
  1032.     super.setEnabled(b);
  1033.     repaint();
  1034.     }
  1035.  
  1036.     /**
  1037.      * Returns true if the focus can be traversed.  This would be false
  1038.      * for components like a disabled button.
  1039.      *
  1040.      * @return true if the focus is traversable
  1041.      */
  1042.     public boolean isFocusTraversable() {
  1043.         return isEnabled();
  1044.     }
  1045.  
  1046.     /**
  1047.      * Processes any key events that the component itself 
  1048.      * recognizes.  This will be called after the focus
  1049.      * manager and any interested listeners have been
  1050.      * given a chance to steal away the event.  This 
  1051.      * method will only be called is the event has not
  1052.      * yet been consumed.  This method is called prior
  1053.      * to the keyboard UI logic.
  1054.      * <p>
  1055.      * This is implemented to take a default action, typically
  1056.      * inserting the character into the document as content.  Subclasses
  1057.      * would normally override this method if they process some
  1058.      * key events themselves.  If the event is processed,
  1059.      * it should be consumed.
  1060.      *
  1061.      * @param e the event
  1062.      */
  1063.     protected void processComponentKeyEvent(KeyEvent e) {
  1064.         int id = e.getID();
  1065.         switch(id) {
  1066.         case KeyEvent.KEY_TYPED:
  1067.             if (mapEventToAction(e) == false) {
  1068.                 // default behavior is to input translated
  1069.                 // characters as content if the character
  1070.                 // hasn't been mapped in the keymap.
  1071.                 Keymap binding = getKeymap();
  1072.                     if (binding != null) {
  1073.                         Action a = binding.getDefaultAction();
  1074.                         if (a != null) {
  1075.                             ActionEvent ae = new ActionEvent(this, 
  1076.                                                              ActionEvent.ACTION_PERFORMED, 
  1077.                                                              String.valueOf(e.getKeyChar()),
  1078.                                                              e.getModifiers());
  1079.                             a.actionPerformed(ae);
  1080.                             e.consume();
  1081.                         }
  1082.                     }
  1083.             }
  1084.             break;
  1085.         case KeyEvent.KEY_PRESSED:
  1086.             mapEventToAction(e);
  1087.             break;
  1088.         case KeyEvent.KEY_RELEASED:
  1089.             mapEventToAction(e);
  1090.             break;
  1091.         }
  1092.     } 
  1093.  
  1094.     // --- java.awt.TextComponent methods ------------------------
  1095.  
  1096.     /**
  1097.      * Sets the position of the text insertion caret for the TextComponent.
  1098.      * Note that the caret tracks change, so this may move if the underlying
  1099.      * text of the component is changed.  If the document is null, does
  1100.      * nothing.
  1101.      *
  1102.      * @param position the position
  1103.      * @beaninfo
  1104.      * description: the caret position
  1105.      */
  1106.     public void setCaretPosition(int position) {
  1107.         Document doc = getDocument();
  1108.         if (doc != null) {
  1109.         if (position > doc.getLength() || position < 0) {
  1110.         throw new IllegalArgumentException("bad position: " + position);
  1111.         }
  1112.             caret.setDot(position);
  1113.         }
  1114.     }
  1115.  
  1116.     /**
  1117.      * Returns the position of the text insertion caret for the 
  1118.      * text component.
  1119.      *
  1120.      * @return the position of the text insertion caret for the
  1121.      *  text component >= 0
  1122.      */
  1123.     public int getCaretPosition() {
  1124.         return caret.getDot();
  1125.     }
  1126.  
  1127.     /**
  1128.      * Sets the text of this TextComponent to the specified text.  If the
  1129.      * text is null or empty, has the effect of simply deleting the old text.
  1130.      * <p>
  1131.      * This method is thread safe, although most Swing methods
  1132.      * are not. Please see 
  1133.      * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
  1134.      * and Swing</A> for more information.     
  1135.      *
  1136.      * @param t the new text to be set
  1137.      * @see #getText
  1138.      * @beaninfo
  1139.      * description: the text of this component
  1140.      */
  1141.     public void setText(String t) {
  1142.         try {
  1143.             Document doc = getDocument();
  1144.             doc.remove(0, doc.getLength());
  1145.             doc.insertString(0, t, null);
  1146.         } catch (BadLocationException e) {
  1147.             getToolkit().beep();
  1148.         }
  1149.     }
  1150.  
  1151.     /**
  1152.      * Returns the text contained in this TextComponent.  If the underlying
  1153.      * document is null, will give a NullPointerException.
  1154.      *
  1155.      * @return the text
  1156.      * @see #setText
  1157.      */
  1158.     public String getText() {
  1159.         Document doc = getDocument();
  1160.         String txt;
  1161.         try {
  1162.             txt = doc.getText(0, doc.getLength());
  1163.         } catch (BadLocationException e) {
  1164.             txt = null;
  1165.         }
  1166.         return txt;
  1167.     }
  1168.  
  1169.     /**
  1170.      * Returns the selected text contained in this TextComponent.  If
  1171.      * the selection is null or the document empty, returns null.
  1172.      *
  1173.      * @return the text
  1174.      * @exception IllegalArgumentException if the selection doesn't
  1175.      *  have a valid mapping into the document for some reason
  1176.      * @see #setText
  1177.      */
  1178.     public String getSelectedText() {
  1179.         String txt = null;
  1180.         int p0 = Math.min(caret.getDot(), caret.getMark());
  1181.         int p1 = Math.max(caret.getDot(), caret.getMark());
  1182.         if (p0 != p1) {
  1183.             try {
  1184.                 Document doc = getDocument();
  1185.                 txt = doc.getText(p0, p1 - p0);
  1186.             } catch (BadLocationException e) {
  1187.         throw new IllegalArgumentException(e.getMessage());
  1188.             }
  1189.         }
  1190.         return txt;
  1191.     }
  1192.  
  1193.     /**
  1194.      * Returns the boolean indicating whether this TextComponent is
  1195.      * editable or not.
  1196.      *
  1197.      * @return the boolean value
  1198.      * @see #setEditable
  1199.      */
  1200.     public boolean isEditable() {
  1201.         return editable;
  1202.     }
  1203.  
  1204.     /**
  1205.      * Sets the specified boolean to indicate whether or not this
  1206.      * TextComponent should be editable.  A PropertyChange event ("editable")
  1207.      * is fired when the state is changed.
  1208.      *
  1209.      * @param b the boolean to be set
  1210.      * @see #isEditable
  1211.      * @beaninfo
  1212.      * description: specifies if the text can be edited
  1213.      */
  1214.     public void setEditable(boolean b) {
  1215.         boolean oldVal = editable;
  1216.         editable = b;
  1217.     firePropertyChange("editable", new Boolean(oldVal), new Boolean(editable));
  1218.     }
  1219.  
  1220.     /**
  1221.      * Returns the selected text's start position.  Return 0 for an
  1222.      * empty document, or the value of dot if no selection.
  1223.      *
  1224.      * @return the start position >= 0
  1225.      */
  1226.     public int getSelectionStart() {
  1227.         int start = Math.min(caret.getDot(), caret.getMark());
  1228.         return start;
  1229.     }
  1230.  
  1231.     /**
  1232.      * Sets the selection start to the specified position.  The new
  1233.      * starting point is constrained to be before or at the current
  1234.      * selection end.
  1235.      * <p>
  1236.      * This is available for backward compatiblitity to code 
  1237.      * that called this method on java.awt.TextComponent.  This is
  1238.      * implemented to forward to the Caret implementation which
  1239.      * is where the actual selection is maintained.
  1240.      *
  1241.      * @param selectionStart the start position of the text >= 0
  1242.      * @beaninfo
  1243.      * description: starting location of the selection.
  1244.      */
  1245.     public void setSelectionStart(int selectionStart) {
  1246.         /* Route through select method to enforce consistent policy
  1247.          * between selectionStart and selectionEnd.
  1248.          */
  1249.         select(selectionStart, getSelectionEnd());
  1250.     }
  1251.  
  1252.     /**
  1253.      * Returns the selected text's end position.  Return 0 if the document
  1254.      * is empty, or the value of dot if there is no selection.
  1255.      *
  1256.      * @return the end position >= 0
  1257.      */
  1258.     public int getSelectionEnd() {
  1259.         int end = Math.max(caret.getDot(), caret.getMark());
  1260.         return end;
  1261.     }
  1262.  
  1263.     /**
  1264.      * Sets the selection end to the specified position.  The new
  1265.      * end point is constrained to be at or after the current
  1266.      * selection start.
  1267.      * <p>
  1268.      * This is available for backward compatiblitity to code 
  1269.      * that called this method on java.awt.TextComponent.  This is
  1270.      * implemented to forward to the Caret implementation which
  1271.      * is where the actual selection is maintained.
  1272.      *
  1273.      * @param selectionEnd the end position of the text >= 0
  1274.      * @beaninfo
  1275.      * description: ending location of the selection.
  1276.      */
  1277.     public void setSelectionEnd(int selectionEnd) {
  1278.         /* Route through select method to enforce consistent policy
  1279.          * between selectionStart and selectionEnd.
  1280.          */
  1281.         select(getSelectionStart(), selectionEnd);
  1282.     }
  1283.     
  1284.     /**
  1285.      * Selects the text found between the specified start and end 
  1286.      * locations.  This call is provided for backward compatibility.
  1287.      * It is routed to a call to setCaretPosition
  1288.      * followed by a call to moveCaretPostion.  The preferred way
  1289.      * to manage selection is by calling those methods directly.
  1290.      *
  1291.      * @param selectionStart the start position of the text >= 0
  1292.      * @param selectionEnd the end position of the text >= 0
  1293.      * @see setCaretPosition
  1294.      * @see moveCaretPosition
  1295.      */
  1296.     public void select(int selectionStart, int selectionEnd) {
  1297.         setCaretPosition(selectionStart);
  1298.         moveCaretPosition(selectionEnd);
  1299.     }
  1300.  
  1301.     /**
  1302.      * Selects all the text in the TextComponent.  Does nothing on a null
  1303.      * or empty document.
  1304.      */
  1305.     public void selectAll() {
  1306.         Document doc = getDocument();
  1307.         if (doc != null) {
  1308.             setCaretPosition(0);
  1309.             moveCaretPosition(doc.getLength());
  1310.         }
  1311.     }
  1312.  
  1313.     // --- Scrollable methods ---------------------------------------------
  1314.  
  1315.     /**
  1316.      * Returns the preferred size of the viewport for a view component.
  1317.      * This is implemented to do the default behavior of returning
  1318.      * the preferred size of the component.
  1319.      * 
  1320.      * @return The preferredSize of a JViewport whose view is this Scrollable.
  1321.      */
  1322.     public Dimension getPreferredScrollableViewportSize() {
  1323.         return getPreferredSize();
  1324.     }
  1325.  
  1326.  
  1327.     /**
  1328.      * Components that display logical rows or columns should compute
  1329.      * the scroll increment that will completely expose one new row
  1330.      * or column, depending on the value of orientation.  Ideally, 
  1331.      * components should handle a partially exposed row or column by 
  1332.      * returning the distance required to completely expose the item.
  1333.      * <p>
  1334.      * The default implementation of this is to simply return 10% of
  1335.      * the visible area.  Subclasses are likely to be able to provide
  1336.      * a much more reasonable value.
  1337.      * 
  1338.      * @param visibleRect The view area visible within the viewport
  1339.      * @param orientation Either SwingConstants.VERTICAL or
  1340.      *   SwingConstants.HORIZONTAL.
  1341.      * @param direction Less than zero to scroll up/left, greater than
  1342.      *   zero for down/right.
  1343.      * @return The "unit" increment for scrolling in the specified direction
  1344.      * @exception IllegalArgumentException for an invalid orientation
  1345.      * @see JScrollBar#setUnitIncrement
  1346.      */
  1347.     public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
  1348.         switch(orientation) {
  1349.         case SwingConstants.VERTICAL:
  1350.             return visibleRect.height / 10;
  1351.         case SwingConstants.HORIZONTAL:
  1352.             return visibleRect.width / 10;
  1353.         default:
  1354.             throw new IllegalArgumentException("Invalid orientation: " + orientation);
  1355.         }
  1356.     }
  1357.  
  1358.  
  1359.     /**
  1360.      * Components that display logical rows or columns should compute
  1361.      * the scroll increment that will completely expose one block
  1362.      * of rows or columns, depending on the value of orientation. 
  1363.      * <p>
  1364.      * The default implementation of this is to simply return the visible
  1365.      * area.  Subclasses will likely be able to provide a much more 
  1366.      * reasonable value.
  1367.      * 
  1368.      * @param visibleRect The view area visible within the viewport
  1369.      * @param orientation Either SwingConstants.VERTICAL or
  1370.      *   SwingConstants.HORIZONTAL.
  1371.      * @param direction Less than zero to scroll up/left, greater than zero
  1372.      *  for down/right.
  1373.      * @return The "block" increment for scrolling in the specified direction.
  1374.      * @exception IllegalArgumentException for an invalid orientation
  1375.      * @see JScrollBar#setBlockIncrement
  1376.      */
  1377.     public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
  1378.         switch(orientation) {
  1379.         case SwingConstants.VERTICAL:
  1380.             return visibleRect.height;
  1381.         case SwingConstants.HORIZONTAL:
  1382.             return visibleRect.width;
  1383.         default:
  1384.             throw new IllegalArgumentException("Invalid orientation: " + orientation);
  1385.         }
  1386.     }  
  1387.     
  1388.  
  1389.     /**
  1390.      * Return true if a viewport should always force the width of this 
  1391.      * Scrollable to match the width of the viewport.  For example a normal 
  1392.      * text view that supported line wrapping would return true here, since it
  1393.      * would be undesirable for wrapped lines to disappear beyond the right
  1394.      * edge of the viewport.  Note that returning true for a Scrollable
  1395.      * whose ancestor is a JScrollPane effectively disables horizontal
  1396.      * scrolling.
  1397.      * <p>
  1398.      * Scrolling containers, like JViewport, will use this method each 
  1399.      * time they are validated.  
  1400.      * 
  1401.      * @return true if a viewport should force the Scrollables
  1402.      *   width to match its own.
  1403.      */
  1404.     public boolean getScrollableTracksViewportWidth() {
  1405.         return false;
  1406.     }
  1407.  
  1408.     /**
  1409.      * Return true if a viewport should always force the height of this 
  1410.      * Scrollable to match the height of the viewport.  For example a 
  1411.      * columnar text view that flowed text in left to right columns 
  1412.      * could effectively disable vertical scrolling by returning
  1413.      * true here.
  1414.      * <p>
  1415.      * Scrolling containers, like JViewport, will use this method each 
  1416.      * time they are validated.  
  1417.      * 
  1418.      * @return true if a viewport should force the Scrollables height
  1419.      *   to match its own.
  1420.      */
  1421.     public boolean getScrollableTracksViewportHeight() {
  1422.         return false;
  1423.     }
  1424.  
  1425. /////////////////
  1426. // Accessibility support
  1427. ////////////////
  1428.  
  1429.  
  1430.     /**
  1431.      * Gets the AccessibleContext associated with this JComponent.
  1432.      * A new context is created if necessary.
  1433.      *
  1434.      * @return the AccessibleContext of this JComponent
  1435.      */
  1436.     public AccessibleContext getAccessibleContext() {
  1437.         if (accessibleContext == null) {
  1438.             accessibleContext = new AccessibleJTextComponent();
  1439.         }
  1440.         return accessibleContext;
  1441.     }
  1442.  
  1443.     /**
  1444.      * Accessibility implementation for JTextComponent.
  1445.      * <p>
  1446.      * Warning: serialized objects of this class will not be compatible with
  1447.      * future swing releases.  The current serialization support is appropriate
  1448.      * for short term storage or RMI between Swing1.0 applications.  It will
  1449.      * not be possible to load serialized Swing1.0 objects with future releases
  1450.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  1451.      * baseline for the serialized form of Swing objects.
  1452.      */
  1453.     public class AccessibleJTextComponent extends AccessibleJComponent 
  1454.     implements AccessibleText, CaretListener, DocumentListener {
  1455.  
  1456.         int caretPos;
  1457.  
  1458.         /**
  1459.          * Constructs an AccessibleJTextComponent.  Adds a listener to track
  1460.          * caret change.
  1461.          */
  1462.         public AccessibleJTextComponent() {
  1463.             Document doc = JTextComponent.this.getDocument();
  1464.             if (doc != null) {
  1465.                 doc.addDocumentListener(this);
  1466.             }
  1467.             JTextComponent.this.addCaretListener(this);
  1468.             caretPos = getCaretPosition();
  1469.         }
  1470.  
  1471.         /**
  1472.          * Handles caret updates (fire appropriate property change event,
  1473.          * which are AccessibleContext.ACCESSIBLE_CARET_PROPERTY and
  1474.          * AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY).
  1475.          * This keeps track of the dot position internally.  When the caret
  1476.          * moves, the internal position is updated after firing the event.
  1477.          *
  1478.          * @param e the CaretEvent
  1479.          */
  1480.         public void caretUpdate(CaretEvent e) {
  1481.             int dot = e.getDot();
  1482.             int mark = e.getMark();
  1483.             if (caretPos != dot) {
  1484.                 // the caret moved
  1485.                 firePropertyChange(ACCESSIBLE_CARET_PROPERTY,
  1486.                     new Integer(caretPos), new Integer(dot));
  1487.                 caretPos = dot;
  1488.             }
  1489.             if (mark != dot) {
  1490.                 // there is a selection
  1491.                 firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, null, 
  1492.                     getSelectedText());
  1493.             }
  1494.         }
  1495.  
  1496.         // DocumentListener methods
  1497.  
  1498.         /**
  1499.          * Handles document insert (fire appropriate property change event
  1500.          * which is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY).
  1501.          * This tracks the dot via the event.
  1502.          *
  1503.          * @param e the DocumentEvent
  1504.          */
  1505.         public void insertUpdate(DocumentEvent e) {
  1506.             Caret c = JTextComponent.this.getCaret();
  1507.             Integer dot = new Integer(c.getDot());
  1508.             firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, dot);
  1509.         }
  1510.  
  1511.         /**
  1512.          * Handles document remove (fire appropriate property change event,
  1513.          * which is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY).
  1514.          * This tracks the dot via the event.
  1515.          *
  1516.          * @param e the DocumentEvent
  1517.          */
  1518.         public void removeUpdate(DocumentEvent e) {
  1519.             Caret c = JTextComponent.this.getCaret();
  1520.             Integer dot = new Integer(c.getDot());
  1521.             firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, dot);
  1522.         }
  1523.  
  1524.         /**
  1525.          * Handles document remove (fire appropriate property change event,
  1526.          * which is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY).
  1527.          * This tracks the dot via the event.
  1528.          *
  1529.          * @param e the DocumentEvent
  1530.          */
  1531.         public void changedUpdate(DocumentEvent e) {
  1532.             Caret c = JTextComponent.this.getCaret();
  1533.             Integer dot = new Integer(c.getDot());
  1534.             firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, dot);
  1535.         }
  1536.  
  1537.         /**
  1538.          * Gets the state set of the JTextComponent.  
  1539.          * The AccessibleStateSet of an object is composed of a set of 
  1540.          * unique AccessibleState's.  A change in the AccessibleStateSet 
  1541.          * of an object will cause a PropertyChangeEvent to be fired
  1542.          * for the AccessibleContext.ACCESSIBLE_STATE_PROPERTY property.
  1543.          *
  1544.          * @return an instance of AccessibleStateSet containing the
  1545.          * current state set of the object
  1546.          * @see AccessibleStateSet
  1547.          * @see AccessibleState
  1548.          * @see #addPropertyChangeListener
  1549.          */
  1550.         public AccessibleStateSet getAccessibleStateSet() {
  1551.             AccessibleStateSet states = super.getAccessibleStateSet();
  1552.             if (JTextComponent.this.isEditable()) {
  1553.                 states.add(AccessibleState.EDITABLE);
  1554.             }
  1555.             return states;
  1556.         }
  1557.  
  1558.  
  1559.         /**
  1560.          * Gets the role of this object.
  1561.          *
  1562.          * @return an instance of AccessibleRole describing the role of the 
  1563.          * object (AccessibleRole.TEXT)
  1564.          * @see AccessibleRole
  1565.          */
  1566.         public AccessibleRole getAccessibleRole() {
  1567.             return AccessibleRole.TEXT;
  1568.         }
  1569.  
  1570.         /**
  1571.          * Gets the AccessibleText interface associated with this object.
  1572.          *
  1573.          * @return an instance of AccessibleText 
  1574.          */
  1575.         public AccessibleText getAccessibleText() {
  1576.             return this;
  1577.         }
  1578.  
  1579.  
  1580.         // --- interface AccessibleText methods ------------------------
  1581.  
  1582.         /**
  1583.          * Many of these methods are just convenience methods; they
  1584.          * just call the equivalent on the parent
  1585.          */
  1586.  
  1587.         /**
  1588.          * Given a point in local coordinates, return the zero-based index
  1589.          * of the character under that Point.  If the point is invalid,
  1590.          * this method returns -1.
  1591.          *
  1592.          * @param p the Point in local coordinates
  1593.          * @return the zero-based index of the character under Point p.
  1594.          */
  1595.         public int getIndexAtPoint(Point p) {
  1596.             if (p == null) {
  1597.                 return -1;
  1598.             }
  1599.             return JTextComponent.this.viewToModel(p);
  1600.         }
  1601.  
  1602.         /**
  1603.          * Determines the bounding box of the character at the given
  1604.          * index into the string.  The bounds are returned in local
  1605.          * coordinates.  If the index is invalid a null rectangle
  1606.          * is returned.
  1607.          *
  1608.          * @param i the index into the String >= 0
  1609.          * @return the screen coordinates of the character's bounding box
  1610.          */
  1611.         public Rectangle getCharacterBounds(int i) {
  1612.             if (i < 0 || i > model.getLength()-1) {
  1613.                 return null;
  1614.             }
  1615.             Rectangle rect;
  1616.             try {
  1617.                 rect = modelToView(i);
  1618.             } catch (BadLocationException e) {
  1619.                 rect = null;
  1620.             }
  1621.             return rect;
  1622.         }
  1623.  
  1624.         /**
  1625.          * Returns the number of characters (valid indicies)
  1626.          *
  1627.          * @return the number of characters >= 0
  1628.          */
  1629.         public int getCharCount() {
  1630.             return model.getLength();
  1631.         }
  1632.  
  1633.         /**
  1634.          * Returns the zero-based offset of the caret.
  1635.          *
  1636.          * Note: The character to the right of the caret will have the
  1637.          * same index value as the offset (the caret is between
  1638.          * two characters).
  1639.          *
  1640.          * @return the zero-based offset of the caret.
  1641.          */
  1642.         public int getCaretPosition() {
  1643.             return JTextComponent.this.getCaretPosition();
  1644.         }
  1645.  
  1646.         /**
  1647.          * Returns the AttributeSet for a given character (at a given index).
  1648.          *
  1649.          * @param i the zero-based index into the text
  1650.          * @return the AttributeSet of the character
  1651.          */
  1652.         public AttributeSet getCharacterAttribute(int i) {
  1653.             Element e = null;
  1654.             for (e = model.getDefaultRootElement(); ! e.isLeaf(); ) {
  1655.                 int index = e.getElementIndex(i);
  1656.                 e = e.getElement(index);
  1657.             }
  1658.             return e.getAttributes();
  1659.         }
  1660.  
  1661.         /**
  1662.          * Returns the start offset within the selected text.
  1663.          * If there is no selection, but there is
  1664.          * a caret, the start and end offsets will be the same.
  1665.          * Return 0 if the text is empty, or the caret position
  1666.          * if no selection.
  1667.          *
  1668.          * @return the index into the text of the start of the selection >= 0
  1669.          */
  1670.         public int getSelectionStart() {
  1671.             return JTextComponent.this.getSelectionStart();
  1672.         }
  1673.  
  1674.         /**
  1675.          * Returns the end offset within the selected text.
  1676.          * If there is no selection, but there is
  1677.          * a caret, the start and end offsets will be the same.
  1678.          * Return 0 if the text is empty, or the caret position
  1679.          * if no selection.
  1680.          *
  1681.          * @return the index into teh text of the end of the selection >= 0
  1682.          */
  1683.         public int getSelectionEnd() {
  1684.             return JTextComponent.this.getSelectionEnd();
  1685.         }
  1686.  
  1687.         /**
  1688.          * Returns the portion of the text that is selected.
  1689.          *
  1690.          * @return the text, null if no selection
  1691.          */
  1692.         public String getSelectedText() {
  1693.             return JTextComponent.this.getSelectedText();
  1694.         }
  1695.  
  1696.         /**
  1697.          * Returns the String at a given index. 
  1698.          *
  1699.          * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
  1700.          * or AccessibleText.SENTENCE to retrieve
  1701.          * @param index an index within the text >= 0
  1702.          * @return the letter, word, or sentence,
  1703.          *   null for an invalid index or part
  1704.          */
  1705.         public String getAtIndex(int part, int index) {
  1706.             if (index < 0 || index > model.getLength()-1) {
  1707.                 return null;
  1708.             }
  1709.             switch (part) {
  1710.             case AccessibleText.CHARACTER:
  1711.                 try {
  1712.                     return model.getText(index, 1);
  1713.                 } catch (BadLocationException e) {
  1714.                     return null;
  1715.                 }
  1716.             case AccessibleText.WORD:
  1717.                 try {
  1718.                     String s = model.getText(0, model.getLength());
  1719.                     BreakIterator words = BreakIterator.getWordInstance();
  1720.                     words.setText(s);
  1721.                     int end = words.following(index);
  1722.                     return s.substring(words.previous(), end);
  1723.                 } catch (BadLocationException e) {
  1724.                     return null;
  1725.                 }
  1726.             case AccessibleText.SENTENCE:
  1727.                 try {
  1728.                     String s = model.getText(0, model.getLength());
  1729.                     BreakIterator sentence = BreakIterator.getSentenceInstance();
  1730.                     sentence.setText(s);
  1731.                     int end = sentence.following(index);
  1732.                     return s.substring(sentence.previous(), end);
  1733.                 } catch (BadLocationException e) {
  1734.                     return null;
  1735.                 }
  1736.             default:
  1737.                 return null;
  1738.             }
  1739.         }
  1740.  
  1741.         /**
  1742.          * Returns the String after a given index.
  1743.          *
  1744.          * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
  1745.          * or AccessibleText.SENTENCE to retrieve
  1746.          * @param index an index within the text >= 0
  1747.          * @return the letter, word, or sentence, null for an invalid
  1748.          *  index or part
  1749.          */
  1750.         public String getAfterIndex(int part, int index) {
  1751.             if (index < 0 || index > model.getLength()-1) {
  1752.                 return null;
  1753.             }
  1754.             switch (part) {
  1755.             case AccessibleText.CHARACTER:
  1756.                 try {
  1757.                     return model.getText(index+1, 1);
  1758.                 } catch (BadLocationException e) {
  1759.                     return null;
  1760.                 }
  1761.             case AccessibleText.WORD:
  1762.                 try {
  1763.                     String s = model.getText(0, model.getLength());
  1764.                     BreakIterator words = BreakIterator.getWordInstance();
  1765.                     words.setText(s);
  1766.                     int start = words.following(index);
  1767.                     return s.substring(start, words.following(start));
  1768.                 } catch (BadLocationException e) {
  1769.                     return null;
  1770.                 }
  1771.             case AccessibleText.SENTENCE:
  1772.                 try {
  1773.                     String s = model.getText(0, model.getLength());
  1774.                     BreakIterator sentence = BreakIterator.getSentenceInstance();
  1775.                     sentence.setText(s);
  1776.                     int start = sentence.following(index);
  1777.                     return s.substring(start, sentence.following(start));
  1778.                 } catch (BadLocationException e) {
  1779.                     return null;
  1780.                 }
  1781.             default:
  1782.                 return null;
  1783.             }
  1784.         }
  1785.  
  1786.  
  1787.         /**
  1788.          * Returns the String before a given index.
  1789.          *
  1790.          * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
  1791.          *   or AccessibleText.SENTENCE to retrieve
  1792.          * @param index an index within the text >= 0
  1793.          * @return the letter, word, or sentence, null for an invalid index
  1794.          *  or part
  1795.          */
  1796.         public String getBeforeIndex(int part, int index) {
  1797.             if (index < 0 || index > model.getLength()-1) {
  1798.                 return null;
  1799.             }
  1800.             switch (part) {
  1801.             case AccessibleText.CHARACTER:
  1802.                 try {
  1803.                     return model.getText(index-1, 1);
  1804.                 } catch (BadLocationException e) {
  1805.                     return null;
  1806.                 }
  1807.             case AccessibleText.WORD:
  1808.                 try {
  1809.                     String s = model.getText(0, model.getLength());
  1810.                     BreakIterator words = BreakIterator.getWordInstance();
  1811.                     words.setText(s);
  1812.                     int end = words.next(index);
  1813.                     end = words.previous();
  1814.                     return s.substring(words.previous(), end);
  1815.                 } catch (BadLocationException e) {
  1816.                     return null;
  1817.                 }
  1818.             case AccessibleText.SENTENCE:
  1819.                 try {
  1820.                     String s = model.getText(0, model.getLength());
  1821.                     BreakIterator sentence = BreakIterator.getSentenceInstance();
  1822.                     sentence.setText(s);
  1823.                     int end = sentence.next(index);
  1824.                     end = sentence.previous();
  1825.                     return s.substring(sentence.previous(), end);
  1826.                 } catch (BadLocationException e) {
  1827.                     return null;
  1828.                 }
  1829.             default:
  1830.                 return null;
  1831.             }
  1832.         }
  1833.  
  1834.     }
  1835.  
  1836.  
  1837.     // --- serialization ---------------------------------------------
  1838.  
  1839.     private void readObject(ObjectInputStream s)
  1840.       throws ClassNotFoundException, IOException 
  1841.     {
  1842.         s.defaultReadObject();
  1843.         caretEvent = new MutableCaretEvent(this);
  1844.         addMouseListener(caretEvent);
  1845.         addFocusListener(caretEvent);
  1846.  
  1847.         // PENDING(prinz)
  1848.         // This should really be updateUI(), but the ui
  1849.         // is currently being serialized so we'll use it.
  1850.         getUI().installUI(this);
  1851.     }
  1852.  
  1853.     // --- member variables ----------------------------------
  1854.  
  1855.     /**
  1856.      * The document model.
  1857.      */
  1858.     private Document model;
  1859.  
  1860.     /**
  1861.      * The caret used to display the insert position
  1862.      * and navigate throught the document. 
  1863.      *
  1864.      * PENDING(prinz)  
  1865.      * This should be serializable, default installed
  1866.      * by UI.
  1867.      */
  1868.     private transient Caret caret;
  1869.  
  1870.     /**
  1871.      * The object responsible for managing highlights.
  1872.      *
  1873.      * PENDING(prinz)  
  1874.      * This should be serializable, default installed
  1875.      * by UI.
  1876.      */
  1877.     private transient Highlighter highlighter;
  1878.  
  1879.     /**
  1880.      * The current key bindings in effect.
  1881.      *
  1882.      * PENDING(prinz)  
  1883.      * This should be serializable, default installed
  1884.      * by UI.
  1885.      */
  1886.     private transient Keymap keymap;
  1887.  
  1888.     /**
  1889.      * is the component opaque?
  1890.      */
  1891.     private boolean opaque;
  1892.  
  1893.     private transient MutableCaretEvent caretEvent;
  1894.     private Color caretColor;
  1895.     private Color selectionColor;
  1896.     private Color selectedTextColor;
  1897.     private Color disabledTextColor;
  1898.     private boolean editable;
  1899.     private Insets margin;
  1900.     private char focusAccelerator;
  1901.     private Action focusAction = new FocusAction();
  1902.  
  1903.     private static ClipboardOwner defaultClipboardOwner = new ClipboardObserver();
  1904.  
  1905.     static class ClipboardObserver implements ClipboardOwner {
  1906.  
  1907.         public void lostOwnership(Clipboard clipboard, Transferable contents) {
  1908.         }
  1909.     }
  1910.  
  1911.     /**
  1912.      * package level access to focused text component
  1913.      * so that JTextAction implementations can be 
  1914.      * reused across JTextComponent implementations.
  1915.      */
  1916.     static final JTextComponent getFocusedComponent() {
  1917.         return focusedComponent;
  1918.     }
  1919.  
  1920.     private static Hashtable keymapTable = null;
  1921.     private JTextComponent editor;
  1922.     private static JTextComponent focusedComponent;
  1923.  
  1924.     static class DefaultKeymap implements Keymap {
  1925.  
  1926.         DefaultKeymap(String nm, Keymap parent) {
  1927.             this.nm = nm; 
  1928.             this.parent = parent;
  1929.             bindings = new Hashtable();
  1930.         }
  1931.  
  1932.         /**
  1933.          * Fetch the default action to fire if a 
  1934.          * key is typed (ie a KEY_TYPED KeyEvent is received)
  1935.          * and there is no binding for it.  Typically this
  1936.          * would be some action that inserts text so that 
  1937.          * the keymap doesn't require an action for each 
  1938.          * possible key.
  1939.          */
  1940.         public Action getDefaultAction() {
  1941.             if (defaultAction != null) {
  1942.                 return defaultAction;
  1943.             }
  1944.             return (parent != null) ? parent.getDefaultAction() : null;
  1945.         }
  1946.  
  1947.         /**
  1948.          * Set the default action to fire if a key is typed.
  1949.          */
  1950.         public void setDefaultAction(Action a) {
  1951.             defaultAction = a;
  1952.         }
  1953.  
  1954.         public String getName() {
  1955.             return nm;
  1956.         }
  1957.  
  1958.         public Action getAction(KeyStroke key) {
  1959.             Action a = (Action) bindings.get(key);
  1960.             if ((a == null) && (parent != null)) {
  1961.                 a = parent.getAction(key);
  1962.             }
  1963.             return a;
  1964.         }
  1965.  
  1966.         public KeyStroke[] getBoundKeyStrokes() {
  1967.             KeyStroke[] keys = new KeyStroke[bindings.size()];
  1968.             int i = 0;
  1969.             for (Enumeration e = bindings.keys() ; e.hasMoreElements() ;) {
  1970.                 keys[i++] = (KeyStroke) e.nextElement();
  1971.             }
  1972.             return keys;
  1973.         } 
  1974.  
  1975.         public Action[] getBoundActions() {
  1976.             Action[] actions = new Action[bindings.size()];
  1977.             int i = 0;
  1978.             for (Enumeration e = bindings.elements() ; e.hasMoreElements() ;) {
  1979.                 actions[i++] = (Action) e.nextElement();
  1980.             }
  1981.             return actions;
  1982.         } 
  1983.  
  1984.         public KeyStroke[] getKeyStrokesForAction(Action a) {
  1985.             // TBD
  1986.             return null;
  1987.         }
  1988.  
  1989.         public boolean isLocallyDefined(KeyStroke key) {
  1990.             return bindings.containsKey(key);
  1991.         }
  1992.  
  1993.         public void addActionForKeyStroke(KeyStroke key, Action a) {
  1994.             bindings.put(key, a);
  1995.         }
  1996.  
  1997.         public void removeKeyStrokeBinding(KeyStroke key) {
  1998.             bindings.remove(key);
  1999.         }
  2000.  
  2001.         public void removeBindings() {
  2002.             bindings.clear();
  2003.         }
  2004.  
  2005.         public Keymap getResolveParent() {
  2006.             return parent;
  2007.         }
  2008.  
  2009.         public void setResolveParent(Keymap parent) {
  2010.             this.parent = parent;
  2011.         }
  2012.  
  2013.         /**
  2014.          * String representation of the keymap... potentially 
  2015.          * a very long string.
  2016.          */
  2017.         public String toString() {
  2018.             return "Keymap[" + nm + "]" + bindings;
  2019.         }
  2020.  
  2021.         String nm;
  2022.         Keymap parent;
  2023.         Hashtable bindings;
  2024.         Action defaultAction;
  2025.     }
  2026.  
  2027.     /**
  2028.      * This is the name of the default keymap that will be shared by all
  2029.      * JTextComponent instances unless they have had a different
  2030.      * keymap set. 
  2031.      */
  2032.     public static final String DEFAULT_KEYMAP = "default";
  2033.  
  2034.     /**
  2035.      * Default bindings for the default keymap if no other bindings
  2036.      * are given.  
  2037.      */
  2038.     static final KeyBinding[] defaultBindings = {
  2039.         new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0),
  2040.                        DefaultEditorKit.deletePrevCharAction),
  2041.         new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0),
  2042.                        DefaultEditorKit.deleteNextCharAction),
  2043.         new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
  2044.                        DefaultEditorKit.forwardAction),
  2045.         new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
  2046.                        DefaultEditorKit.backwardAction)
  2047.     };
  2048.  
  2049.     static {
  2050.         try {
  2051.             keymapTable = new Hashtable(17);
  2052.             Keymap binding = addKeymap(DEFAULT_KEYMAP, null);
  2053.             binding.setDefaultAction(new DefaultEditorKit.DefaultKeyTypedAction());
  2054.             EditorKit kit = new DefaultEditorKit();
  2055.             loadKeymap(binding, defaultBindings, kit.getActions());
  2056.         } catch (Throwable e) {
  2057.             e.printStackTrace();
  2058.             keymapTable = new Hashtable(17);
  2059.         }
  2060.     }
  2061.  
  2062.     /**
  2063.      * Event to use when firing a notification of change to caret 
  2064.      * position.  This is mutable so that the event can be reused
  2065.      * since caret events can be fairly high in bandwidth.
  2066.      */
  2067.     static class MutableCaretEvent extends CaretEvent implements ChangeListener, MouseListener, FocusListener {
  2068.  
  2069.         MutableCaretEvent(JTextComponent c) {
  2070.             super(c);
  2071.         }
  2072.  
  2073.         final void fire() {
  2074.             JTextComponent c = (JTextComponent) getSource();
  2075.             if (c != null) {
  2076.                 Caret caret = c.getCaret();
  2077.                 dot = caret.getDot();
  2078.                 mark = caret.getMark();
  2079.                 c.fireCaretUpdate(this);
  2080.             }
  2081.         }
  2082.  
  2083.         public final String toString() {
  2084.             return "dot=" + dot + "," + "mark=" + mark;
  2085.         }
  2086.  
  2087.         // --- CaretEvent methods -----------------------
  2088.  
  2089.         public final int getDot() {
  2090.             return dot;
  2091.         }
  2092.  
  2093.         public final int getMark() {
  2094.             return mark;
  2095.         }
  2096.  
  2097.         // --- ChangeListener methods -------------------
  2098.  
  2099.         public final void stateChanged(ChangeEvent e) {
  2100.             if (! dragActive) {
  2101.                 fire();
  2102.             }
  2103.         }
  2104.  
  2105.         // --- FocusListener methods --------------------------------
  2106.  
  2107.         /**
  2108.          * Stashes the current focused JTextComponent reference
  2109.          * for JTextAction instances to use if the ActionEvent
  2110.          * doesn't contain the target text component.
  2111.          *
  2112.          * @param e the focus event
  2113.          * @see JTextAction
  2114.          * @see FocusListener#focusGained
  2115.          */
  2116.         public void focusGained(FocusEvent e) {
  2117.             focusedComponent = (JTextComponent) getSource();
  2118.         }
  2119.  
  2120.         /**
  2121.          * Removes reference to focused text component that
  2122.          * instances of JTextAction use.
  2123.          *
  2124.          * @param e the focus event
  2125.          * @see JTextAction
  2126.          * @see FocusListener#focusLost
  2127.          */
  2128.         public void focusLost(FocusEvent e) {
  2129.             // temp focus loss from menus causes problems
  2130.             //focusedComponent = null;
  2131.         }
  2132.  
  2133.         // --- MouseListener methods -----------------------------------
  2134.     
  2135.         /**
  2136.          * Requests focus on the associated
  2137.          * text component, and try to set the cursor position.
  2138.          *
  2139.          * @param e the mouse event
  2140.          * @see MouseListener#mousePressed
  2141.          */
  2142.         public final void mousePressed(MouseEvent e) {
  2143.             dragActive = true;
  2144.         }
  2145.  
  2146.         /**
  2147.          * Called when the mouse is released.
  2148.          *
  2149.          * @param e the mouse event
  2150.          * @see MouseListener#mouseReleased
  2151.          */
  2152.         public final void mouseReleased(MouseEvent e) {
  2153.             dragActive = false;
  2154.             fire();
  2155.         }
  2156.  
  2157.         public final void mouseClicked(MouseEvent e) {
  2158.         }
  2159.  
  2160.         public final void mouseEntered(MouseEvent e) {
  2161.         }
  2162.  
  2163.         public final void mouseExited(MouseEvent e) {
  2164.         }
  2165.  
  2166.         private boolean dragActive;
  2167.         private int dot;
  2168.         private int mark;
  2169.     }
  2170.  
  2171.     class FocusAction extends AbstractAction {
  2172.  
  2173.         public void actionPerformed(ActionEvent e) {
  2174.             requestFocus();
  2175.         }
  2176.  
  2177.         public boolean isEnabled() {
  2178.             if(isEditable())
  2179.                 return true;
  2180.             else
  2181.                 return false;
  2182.         }
  2183.     }
  2184. }
  2185.  
  2186.  
  2187.